package przeplywy;

import edu.uci.ics.jung.graph.util.Pair;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.Iterator;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 *
 * @author Robert & Sejk
 */
public class Flow extends JFrame {

    public Map<String, Map<String, Map<String, HelpfullStruct>>> super_map;
    private Vector<String> files_path;
    static private JavaParser parser;
    JTree t;
    DefaultMutableTreeNode tree;
    DefaultMutableTreeNode tmp_tree;
    //tymczasowo
    private static final int width = 400;
    private static final int height = 300;

    public Flow(Vector<String> f, String PackageName, String ClassName, String FunName, String VarName) {
        super_map = new HashMap<String, Map<String, Map<String, HelpfullStruct>>>();
        files_path = f;
        parser = new JavaParser();
        CreateFlowRoot(ClassName, FunName, VarName);
        FillSuperMap();
        Taka();
        GetFlow(PackageName, ClassName, FunName, VarName, 0);

    }

    public void FillSuperMap() {

        //przegladam sciezki do plików, wczytuje pliki do parser, uzupe�niam super mape
        //a tutaj jeszcze ten wektor sciezek
        for (int g = 0; g < files_path.size(); g++) {
            this.parser.SetFileName(files_path.elementAt(g));
            this.parser.Start();
            this.parser.method_id.clear();
            this.parser.Start();

            Map<String, HelpfullStruct> methods = new HashMap<String, HelpfullStruct>();
            int start_a = 0;
            int start_v = 0;
            int start_s = 0;

            for (int k = 0; k < parser.method_id.size(); k++) {
                HelpfullStruct h = new HelpfullStruct();
                for (int i = start_a; i < parser.v3.size(); i++) {
                    if (parser.v3.elementAt(i).getFirst() == " ") {
                        start_a = i + 1;
                        break;
                    } else {
                        h.arguments.add(parser.v3.elementAt(i));
                    }
                }

                for (int i = 0; i < parser.v.size(); i++) {
                    h.arguments.add(parser.v.elementAt(i));
                }

                for (int i = start_s; i < parser.v5.size(); i++) {
                    if (parser.v5.elementAt(i) == " ") {
                        start_s = i + 1;
                        break;
                    } else {
                        h.source.add(parser.v5.elementAt(i));
                    }
                }
                for (int i = start_v; i < parser.v2.size(); i++) {
                    if (parser.v2.elementAt(i).getFirst() == " ") {
                        start_v = i + 1;
                        break;
                    } else {
                        h.variables.add(parser.v2.elementAt(i));
                    }
                }
                methods.put(parser.method_id.elementAt(k), h);

            }

            Map<String, Map<String, HelpfullStruct>> classes = new HashMap<String, Map<String, HelpfullStruct>>();

            classes.put(this.parser.GetClassName(), methods);
            this.super_map.put(this.parser.GetPackageName(), classes);
            System.out.println(super_map.get("Paczka2"));
            
            /*methods.clear();
            classes.clear();
            parser.v.clear();
            parser.v2.clear();
            parser.v3.clear();
            parser.v4.clear();
            parser.v5.clear();*/
        }
        System.out.println(super_map.get("Paczka2"));
        //a na koniec czyszczenie struktur pomocniczych w klasie JavaParser

    }

    public void printSuperMap() {
        //bardziej przyklad uzycia
        for (Map.Entry<String, Map<String, Map<String, HelpfullStruct>>> entry : this.super_map.entrySet()) {
            String key = entry.getKey();
            System.out.println(key + " " + entry.getValue().get("Flow").get("AnalyzeLine").arguments);
            System.out.println(key + " " + entry.getValue().get("Flow").get("printSuperMap").variables);
            System.out.println(key + " " + entry.getValue().get("Flow").get("printSuperMap").source);
        }
    }

    //wyciagamy dane -----------------------------------------------------------
    //wyciagamy kod
    public Vector<String> getFunctionSource(String paczka, String klasa, String funkcja) {
        return super_map.get(paczka).get(klasa).get(funkcja).source;
    }

    //wyciagamy zmienne
    public Vector<Pair> getFunctionVariables(String paczka, String klasa, String funkcja) {
        return super_map.get(paczka).get(klasa).get(funkcja).variables;
    }

    //wyciagamy argumenty
    public Vector<Pair> getFunctionArguments(String paczka, String klasa, String funkcja) {


        if (super_map.get(paczka) != null) {
            if (super_map.get(paczka).get(klasa) != null) {
                if (super_map.get(paczka).get(klasa).get(funkcja) != null) {
                    return (Vector<Pair>) super_map.get(paczka).get(klasa).get(funkcja).arguments.clone();
                }
            }
        }
        return null;
    }

    //sprawdanie czy w super_mapie jest cos tam
    public boolean checkClassAvailability(String pac, String fun) {
        if (super_map.get(pac).get(fun) != null) {
            return true;
        } else {
            return false;
        }
    }

    public String getPackageNameDependingOnClassName(String klasa) {

        String result = "error";
        Iterator it = this.super_map.entrySet().iterator();
        Map<String, HelpfullStruct> tmp = new HashMap<String, HelpfullStruct>();

        while (it.hasNext()) {
            Map.Entry t = (Map.Entry) it.next();
            tmp = (Map<String, HelpfullStruct>) t.getValue();
            Map.Entry t2 = tmp.entrySet().iterator().next();
            if (t2.getKey().toString().compareTo(klasa) == 0) {
                result = t.getKey().toString();
                break;
            } else {
                result = "error";
            }
        }
        return result;
    }

    public static String[] ChangeToNormal(String s) {
        String[] tab = new String[20];
        String zs = null;
        int zp = 0;

        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) != '-') {
                zs = zs + s.charAt(i);
            } else {
                tab[zp] = zs;
                zp++;
            }
        }
        return tab;
    }

    public static void PrintVector(Vector vec) {
        for (int i = 0; i < vec.size(); i++) {
            System.out.print(vec.elementAt(i));
        }
    }

    public static int FindTokenInLineRev(Vector<String> vec, String TokenName) {
        String s;
        int eq;
        for (int i = vec.size() - 1; i >= 0; i--) {
            s = vec.elementAt(i);
            eq = s.compareTo(TokenName);
            if (eq == 0) {
                return i;
            }
        }
        return -1;
    }

    public static int FindTokenInLine(Vector<String> vec, String TokenName) {
        String s;
        int eq;
        for (int i = 0; i < vec.size(); i++) {
            s = vec.elementAt(i);
            eq = s.compareTo(TokenName);
            if (eq == 0) {
                return i;
            }
        }
        return -1;
    }

    public static boolean isLetterOrDigit(char ch) {
        int asci = (int) ch;
        if (((asci >= 48) && (asci <= 57)) || //liczby
                ((asci >= 65) && (asci <= 90)) || //du�e litery
                ((asci >= 97) && (asci <= 122))) //ma�e litery
        {
            return true;
        } else {
            return false;
        }
    }

    public static boolean IsTokenFunctionCall(String s) {
        boolean ret = true;
        for (int i = 0; i < s.length(); i++) {
            if (!isLetterOrDigit(s.charAt(i))) {
                ret = false;
            }
        }
        if (s.compareTo("if") == 0) {
            ret = false;
        }
        if (s.compareTo("while") == 0) {
            ret = false;
        }
        if (s.compareTo("for") == 0) {
            ret = false;
        }
        return ret;
    }

    public static boolean IsEmpty(String s) {
        if (s.length() == 0) {
            return true;
        }
        if ((s.length() == 1) && (s.charAt(0) == '-')) {
            return true;
        }
        return false;
    }

    public static String CleanString(String s) {
        String ret = "";
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) != '-') {
                ret = ret + s.charAt(i);
            }
        }
        return ret;
    }

    public static String AnalyzeLine(Vector<String> vec, String VarName) {
        int no = 0, no1 = 0, i, zp;
        String ret = "";
        Vector<String> vec_left = new Vector();
        Vector<String> vec_right = new Vector();
        Vector<String> vp = new Vector();

        no = FindTokenInLine(vec, "=");
        if (no != -1) {
            for (i = 0; i < no; i++) {
                vec_left.add(vec.elementAt(i));
            }
            for (i = no + 1; i < vec.size(); i++) {
                vec_right.add(vec.elementAt(i));
            }

            int nor = FindTokenInLine(vec_right, VarName);
            int nol = FindTokenInLine(vec_left, VarName);
            //ret = ret + AnalyzeLine(vec_right, VarName);
            //ret = ret + AnalyzeLine(vec_left, VarName);
            if (nor != -1) {
                if (VarName.compareTo(vec.elementAt(no - 1)) != 0) {
                    ret = ret + AnalyzeLine(vec_right, VarName);
                } else {
                    ret = ret + AnalyzeLine(vec_right, VarName);
                }

            }
        } else {

            int open = 1;
            int numer = 0;
            String o = "(", c = ")", zs = ".";
            no = FindTokenInLine(vec, "(");

            if (no == -1) {
                return "-";
            }

            for (i = no + 1; i < vec.size(); i++) {
                if (o.compareTo(vec.elementAt(i)) == 0) {
                    open++;
                }
                if (c.compareTo(vec.elementAt(i)) == 0) {
                    open--;
                }
                if (open == 0) {
                    no1 = i;
                    break;
                }
                vp.add(vec.elementAt(i));
            }

            if (no == 0) {
                return "-";
            }

            if (FindTokenInLine(vp, VarName) == -1) {
                return "-";
            }

            if (FindTokenInLine(vec, "(") != -1) {
                ret = ret + AnalyzeLine(vp, VarName);
                if (!(IsTokenFunctionCall(vec.elementAt(no - 1)))) {
                    return ret;
                }
                for (i = no + 1; i < no1; i = i + 2) {
                    if ((o.compareTo(vec.elementAt(i + 1)) == 0) ||
                            (zs.compareTo(vec.elementAt(i + 1)) == 0)) {
                        numer = (i - no + 1) / 2;
                        break;
                    }
                    if (VarName.compareTo(vec.elementAt(i)) == 0) {
                        numer = (i - no + 1) / 2;
                    }
                }
                if (no < 3) {
                    ret = ret + "=" + "-" + vec.elementAt(no - 1) + "-" + numer + "-";
                } else {
                    if (zs.compareTo(vec.elementAt(no - 2)) == 0) {
                        if (IsTokenFunctionCall(vec.elementAt(no - 3))) {
                            ret = ret + vec.elementAt(no - 3) + "-" + vec.elementAt(no - 1) + "-" + numer + "-";
                        } else {
                            ret = ret + "=" + "-" + vec.elementAt(no - 1) + "-" + numer + "-";
                        }
                    } else {
                        ret = ret + "=" + "-" + vec.elementAt(no - 1) + "-" + numer + "-";
                    }
                }
            }

        }

        return ret;
    }

    public void Print(String PackageName, String ClassName, String FunName, String VarName, int depth) {


        for (int i = 0; i < depth; i++) {
            System.out.print("  ");
        }
        System.out.println("Przeplyw: " + PackageName + " " + ClassName + " " + FunName + " " + VarName);
        DefaultMutableTreeNode w = new DefaultMutableTreeNode(FunName + "_" + VarName);

        if (depth == 0) {
            tmp_tree = w;
            tree.add(w);
        } else {
            DefaultMutableTreeNode w1 = new DefaultMutableTreeNode(PackageName + "_" + ClassName + "_" + FunName + "_" + VarName);
            tmp_tree.add(w1);
            tree.add(tmp_tree);
        }
    }

    public void CreateFlowRoot(String ClassName, String FunName, String VarName) {
        tree = new DefaultMutableTreeNode(ClassName + "_" + FunName + "_" + VarName);
    }

    public JTree GetTree() {

        return t;
    }

    public void Taka() {
        t = new JTree(tree);

    }
    public void GetFlow(String PackageName, String ClassName, String FunName, String VarName, int depth) {

        System.out.println(PackageName+ " " +ClassName+ " " + FunName + " " + VarName);
        
        Vector<String> v = (Vector<String>) super_map.get(PackageName).get(ClassName).get(FunName).source.clone();

        String NewPackageName = PackageName, NewClassName = ClassName, NewFunName = FunName, NewVarName = VarName;

        Vector<String> tmp_v = new Vector<String>();
        Vector<FlowStruct> f_v = new Vector<FlowStruct>();


        String ow = "{", zw = "}", sr = ";", zp = "";
        for (int i = 0; i < v.size(); i++) {
            if ((ow.compareTo(v.elementAt(i)) == 0) || (zw.compareTo(v.elementAt(i)) == 0) || (sr.compareTo(v.elementAt(i)) == 0)) {
                zp = AnalyzeLine(tmp_v, VarName);
                if (!IsEmpty(zp)) {
                    int count = 0;
                    String c = "";
                    FlowStruct fs = new FlowStruct();
                    for (int z = 1; z < zp.length(); z++) {
                        if (zp.charAt(z) == '-') {
                            count++;
                        } else {
                            if (count == 0) {
                                fs.fisrt = fs.fisrt + zp.charAt(z);
                            }
                            if (count == 1) {
                                fs.second = fs.second + zp.charAt(z);
                            }
                            if (count == 2) {
                                c = c + zp.charAt(z);
                            }
                        }
                    }
                    fs.number = fs.number.parseInt(c);
                    f_v.add(fs);
                }
                tmp_v.clear();
                continue;
            } else {
                tmp_v.add(v.elementAt(i));
            }
        }

        Vector<Pair> v_variable = new Vector<Pair>();

        String typ = "";
        String strpom = "=";

        for (int i = 1; i < f_v.size(); i++) {
            if (strpom.compareTo(f_v.get(i).fisrt) != 0) {
                v_variable = (Vector<Pair>) super_map.get(PackageName).get(ClassName).get(FunName).variables.clone();
                for (int j = 0; j < v_variable.size(); j++) {
                    if (typ.compareTo("") != 0) {
                        break;
                    }
                    if (f_v.get(i).fisrt.compareTo(v_variable.get(j).getSecond().toString()) == 0) {
                        typ = v_variable.get(j).getFirst().toString();
                    }
                }
                if (typ.compareTo("") == 0) {
                    v_variable.clear();
                    v_variable = (Vector<Pair>) super_map.get(PackageName).get(ClassName).get(FunName).arguments.clone();

                    for (int j = 0; j < v_variable.size(); j++) {
                        if (typ.compareTo("") != 0) {
                            break;
                        }
                        if (f_v.get(i).fisrt.compareTo(v_variable.get(j).getSecond().toString()) == 0) {
                            typ = v_variable.get(j).getFirst().toString();
                        }
                    }
                }
            }
            NewFunName = f_v.get(i).second;
            if (typ.compareTo("") != 0) {
                NewClassName = typ;
            }

            String err = "error";
            NewPackageName = getPackageNameDependingOnClassName(NewClassName);
            if (err.compareTo(NewPackageName) == 0) {
                NewPackageName = PackageName;
            }

            v_variable.clear();
            v_variable = getFunctionArguments(NewPackageName, NewClassName, NewFunName);

            if (v_variable != null) {
                int index = f_v.get(i).number - 1;
                NewVarName = v_variable.elementAt(index).getSecond().toString();
                if (NewFunName.compareTo(FunName) == 0) {
                    Print(NewPackageName, NewClassName, NewFunName, NewVarName, depth);
                } else {
                    Print(NewPackageName, NewClassName, NewFunName, NewVarName, depth);
                    GetFlow(NewPackageName, NewClassName, NewFunName, NewVarName, depth + 1);
                }
            } else {
                Print(NewPackageName, NewClassName, NewFunName, NewVarName, depth);
            }
        }
    }
}

